#! /usr/bin/env python


from PyQt4 import QtGui,QtCore
import heapq

class MainWindow(QtGui.QMainWindow):
    def __init__(self):
        super(MainWindow,self).__init__()
        self.setGeometry(100,100,1000,800)
        self.MasterWidget=QtGui.QWidget(self)
        self.MasterLayout = QtGui.QHBoxLayout(self.MasterWidget)
        self.TheGrid = TheGrid(self)
        self.MasterLayout.addWidget(self.TheGrid)
        self.setCentralWidget(self.MasterWidget)
        
class TheGrid(QtGui.QWidget):
    def __init__(self,parent = None):
        super(TheGrid,self).__init__()
        self.MasterLayout = QtGui.QGridLayout()
        self.setLayout(self.MasterLayout)
        self.MasterLayout.setSpacing(0)
        self.Cells = []
#        self.setFixedSize(1000,800)
        gridsize = 30
        for x in range(gridsize):
            self.Cells.append([])
            
            for y in range(gridsize):
                print "x :", x, " y: ",y
                string = "%s-%s" % (x,y)
                temp = Cell(x,y)
                self.Cells[x].append(temp)
                self.MasterLayout.addWidget(temp,y,x)
        button = QtGui.QPushButton('go')
        self.MasterLayout.addWidget(button,gridsize,0,1,gridsize)
        button.clicked.connect(self.GO)
        
    def GO(self):
        startx,starty = self.getStart()
        print "start: %s-%s" % (startx,starty)
        goalx,goaly = self.getGoal()
        print "Goal: %s-%s" % (goalx,goaly)
        path = self.findPath(startx,starty,goalx,goaly)
        
    def getStart(self):
        for i in range(len(self.Cells)):
            for j in range(len(self.Cells[i])):
                if self.Cells[i][j].status == 2:   
                    return self.Cells[i][j].xx,self.Cells[i][j].yy
        return -1,-1

    def getGoal(self):
        for i in range(len(self.Cells)):
            for j in range(len(self.Cells[i])):
                if self.Cells[i][j].status == 3:   
                    return self.Cells[i][j].xx,self.Cells[i][j].yy
        return -1,-1
    
    def findPath(self,startx,starty,goalx,goaly):
        OpenList=[]
        ClosedList=[]
        # calc H for the start cell 
        self.Cells[startx][starty].calcHScore(goalx,goaly)
        self.Cells[startx][starty].calcFScore()
        heapq.heappush(OpenList,(self.Cells[startx][starty].F,self.Cells[startx][starty]))
        # calc H for all cells attached to the start square
        while len(OpenList) > 0:
            currentF,currentcell=heapq.heappop(OpenList)
            ClosedList.append(currentcell)
            for cx in range(0,2,1):
                for cy in range(0,2,1):
                    # we start at the upper left of the attached cells
                    x = (currentcell.xx - 1) + cx
                    y = (currentcell.yy - 1) + cy
                    # does the cell exist 
                    if self.Cells[x][y]:
                        print "found a cell: %s-%s" % (x,y)
                        # check if it is in the closed list:
                        if self.Cells[x][y] in ClosedList:
                            continue
                        # check if it is a wall
                        if self.Cells[x][y].status == 1:
                            continue
                        if self.Cells[x][y].status == 3:
                            ClosedList.append(currentcell)
                            print ClosedList
                            break
                        if self.Cells[x][y] in OpenList:
                            # pass
                            if self.Cells[x][y].G < currentcell.G:
                                self.Cell[x][y].parent = currentcell
                            # recalc G F 
                            # resort
                            
                        else:
                            # set parent to the currentcell
                            self.Cells[x][y].parent = currentcell
                            
                            # not in open list calc F
                            self.Cells[x][y].calcHScore(goalx,goaly)
                            # set G score , the if decides if it is diagonally adjected or not
                            if (x == 0 and y == 0) or (x == 2 and y == 0) or (x == 0 and y == 2) or (x == 2 and y == 2):
                                # its diagonal
                                self.Cells[x][y].G=self.Cells[x][y].parent.G + 14
                            else:
                                # its orthogonal
                                self.Cells[x][y].G=self.Cells[x][y].parent.G + 10
                            self.Cells[x][y].calcFScore()
                            # add it to the openlist heap
                            heapq.heappush(OpenList,(self.Cells[x][y].F,self.Cells[x][y]))
                    else:
                        continue

class Cell(QtGui.QWidget):
    def __init__(self,xx,yy,parent = None):
        super(Cell,self).__init__()
        self.xx = xx
        self.yy = yy
        self.coords = "%s-%s" % (xx,yy) 
        self.status = 0
        # status :
        # 0 empty
        # 1 wall
        # 2 start
        # 3 finish
        self.F = 0
        self.G = 0
        self.H = 0
        
    def paintEvent(self,e):
        painter = QtGui.QPainter(self)
        painter.fillRect(self.rect(),colors[self.status])
        
    def mousePressEvent(self,e):
        print self.coords
        self.status +=1
        if self.status == 4:
            self.status = 0
        self.update()
        
    def calcHScore(self,goalx,goaly):
        print self.xx,goalx,self.yy,goaly
        temp = abs(self.xx - goalx) + abs(self.yy - goaly)
        temp = temp * 10
        self.H = temp
        print "coords: " + self.coords + "H: " + str(self.H)
        
    def calcFScore(self):
        self.F = self.H + self.G
        print "coords: " + self.coords + " F: " + str(self.F)
        
        
        #
Application=QtGui.QApplication([])
pathfinder=MainWindow()
colors=[QtGui.QColor('#AAAAAA'),QtGui.QColor('#000000'),QtGui.QColor('#FF0000'),QtGui.QColor('#00FF00')]
pathfinder.show()
Application.exec_()
